package com.tencent.sr.iris.activity.service.task.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tencent.sr.iris.activity.common.enums.ActivityTaskStatusEnum;
import com.tencent.sr.iris.activity.common.enums.AwardRecordIssueStatusEnum;
import com.tencent.sr.iris.activity.common.enums.TaskBatchDateIsParticipatedEnum;
import com.tencent.sr.iris.activity.common.enums.UserTaskStatusEnum;
import com.tencent.sr.iris.activity.common.util.ShardingIdUtil;
import com.tencent.sr.iris.activity.common.util.TimeUtils;
import com.tencent.sr.iris.activity.domain.event.dto.ActivityDTO;
import com.tencent.sr.iris.activity.domain.event.dto.ActivityTaskDTO;
import com.tencent.sr.iris.activity.domain.event.dto.InviteLimitDTO;
import com.tencent.sr.iris.activity.interfaces.enums.ActivityEventSourceEnum;
import com.tencent.sr.iris.activity.interfaces.enums.ActivityEventTypeEnum;
import com.tencent.sr.iris.activity.interfaces.enums.ActivityIdEnum;
import com.tencent.sr.iris.activity.interfaces.enums.ActivityTaskIdEnum;
import com.tencent.sr.iris.activity.interfaces.enums.OrderStatusEnum;
import com.tencent.sr.iris.activity.interfaces.event.dto.ActivityEventDTO;
import com.tencent.sr.iris.activity.interfaces.message.DistributionOrderEvent;
import com.tencent.sr.iris.activity.interfaces.request.acticity.AwardRecordRequest;
import com.tencent.sr.iris.activity.interfaces.request.acticity.QueryUserTaskRecordFromDBRequest;
import com.tencent.sr.iris.activity.interfaces.request.task.InviteDataFreshRequest;
import com.tencent.sr.iris.activity.interfaces.response.InviteDataFreshResponse;
import com.tencent.sr.iris.activity.repository.Criteria;
import com.tencent.sr.iris.activity.repository.entity.TIrisEventHandingRecordDO;
import com.tencent.sr.iris.activity.repository.entity.TIrisUserTaskRecordDO;
import com.tencent.sr.iris.activity.repository.mapper.TIrisEventHandingRecordMapper;
import com.tencent.sr.iris.activity.repository.mapper.TIrisUserTaskRecordMapper;
import com.tencent.sr.iris.activity.repository.mapper.example.TIrisActivityAwardRecordExample;
import com.tencent.sr.iris.activity.repository.mapper.example.TIrisEventHandingRecordExample;
import com.tencent.sr.iris.activity.repository.mapper.example.TIrisUserTaskRecordExample;
import com.tencent.sr.iris.activity.service.activity.ActivityCommonService;
import com.tencent.sr.iris.activity.service.activity.IrisActivityAwardRecordService;
import com.tencent.sr.iris.activity.service.activity.IrisActivityService;
import com.tencent.sr.iris.activity.service.activity.IrisActivityTaskService;
import com.tencent.sr.iris.activity.service.activity.IrisUserTaskRecordService;
import com.tencent.sr.iris.activity.service.activity.impl.IrisActivityAwardRecordServiceImpl;
import com.tencent.sr.iris.activity.service.config.ActivityConfig;
import com.tencent.sr.iris.activity.service.event.EventExecutorContext;
import com.tencent.sr.iris.activity.service.event.task.IrisTaskExecutor;
import com.tencent.sr.iris.activity.service.event.vo.TaskExecutorExtendInfo;
import com.tencent.sr.iris.activity.service.kafka.listener.UserEventListener;
import com.tencent.sr.iris.activity.service.task.InviteDataFreshTaskService;
import com.tencent.sr.iris.activity.service.util.IdCreateorUtil;
import com.tencent.sr.iris.activity.service.util.LocalDateUtil;
import com.tencent.sr.rmall.springbootstarter.utils.JsonUtils;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class InviteDataFreshTaskServiceImpl implements InviteDataFreshTaskService {

    @Resource
    private TIrisEventHandingRecordMapper eventHandingRecordMapper;

    @Resource
    private ActivityConfig activityConfig;

    @Resource
    private ActivityCommonService activityCommonService;

    @Resource
    private IrisUserTaskRecordService irisUserTaskRecordService;

    @Resource
    private TIrisUserTaskRecordMapper userTaskRecordMapper;

    @Resource
    private IrisActivityService irisActivityService;
    @Resource
    private IrisActivityTaskService irisActivityTaskService;
    @Resource
    private EventExecutorContext eventExecutorContext;

    @Resource
    private IrisActivityAwardRecordServiceImpl activityAwardRecordService;

    @Resource
    UserEventListener userEventListener;

    @Resource
    private IdCreateorUtil idCreateorUtil;

    public List<TIrisEventHandingRecordDO> queryEventHandingRecord(InviteDataFreshRequest request, Integer shardingId){
        //分片获取满足邀请有礼门槛的分销单消息
        TIrisEventHandingRecordExample example = new TIrisEventHandingRecordExample();
        Criteria criteria = example.createCriteria()
                .andPropertyEqualTo(TIrisEventHandingRecordExample.SHARDING_ID, shardingId)
                .andPropertyEqualTo(TIrisEventHandingRecordExample.ACTIVITY_ID,
                        activityConfig.getInviteGiftActivityId())
                .andPropertyEqualTo(TIrisEventHandingRecordExample.TASK_ID
                        , ActivityTaskIdEnum.INVITE_GMV_TASK.getCode())
                .andPropertyEqualTo(TIrisEventHandingRecordExample.EVENT_TYPE,
                        ActivityEventTypeEnum.DISTRIBUTION_ORDER.getCode())
                .andPropertyGreaterThanOrEqualTo(TIrisEventHandingRecordExample.CREATE_TIME, request.getStartTime());

        if (null != request.getEndTime()) {
            criteria.andPropertyLessThanOrEqualTo(TIrisEventHandingRecordExample.CREATE_TIME, request.getEndTime());
        }
        return eventHandingRecordMapper.selectByExample(example);
    }

    /**
     * 查询需要补发邀请有礼奖的uid
     * @param request
     * @return
     */
    @Override
    public InviteDataFreshResponse queryAwardUidList(InviteDataFreshRequest request) {
        InviteDataFreshResponse response = new InviteDataFreshResponse();
        List<TIrisEventHandingRecordDO> listAll = new ArrayList<>();
        Map<String,Object> uidInfoMap = new HashMap<>();
        for (int i = 0; i < 1024; i++) {
            List<TIrisEventHandingRecordDO> list = queryEventHandingRecord(request,i);
            if (!CollectionUtils.isEmpty(list)) {
                List<TIrisEventHandingRecordDO> collect = list.stream().filter(item ->
                        checkEventHandingRecord(item,UserTaskStatusEnum.LIMITED))
                        .collect(Collectors.toList());
                listAll.addAll(collect);
            }
        }
        //将所有满足的交易成功的订单进行排序
        List<String> orderUidList = listAll.stream()
                .map(item -> {
                    ActivityEventDTO orderEventDTO = JsonUtils.parse(item.getEventInfo(), ActivityEventDTO.class);
                    String eventInfoContent = orderEventDTO.getEventInfo();
                    DistributionOrderEvent orderEvent = JsonUtils.parse(eventInfoContent, DistributionOrderEvent.class);
                    uidInfoMap.put(item.getUid(),orderEvent.getFinishTime());
                    return orderEvent;
                })
                .sorted(Comparator.comparingLong(a -> a.getFinishTime()))
                .map(DistributionOrderEvent::getCpsUid)
                .distinct()
                .collect(Collectors.toList());
        response.setUidAwardList(orderUidList);
        response.setUidInfoMap(uidInfoMap);
        response.setTotalNum(orderUidList.size());
        return response;
    }

    @Override
    public InviteDataFreshResponse inviteAwardDeal(InviteDataFreshRequest request) {
        InviteDataFreshResponse response = new InviteDataFreshResponse();
        Set<String> uidSet = new HashSet<>();
        //通过uid列表批量更新
        if (!CollectionUtils.isEmpty(request.getUidList())) {
            List<String> uidList = request.getUidList();
            response.setTotalNum(uidList.size());
            for (int i = 0; i < uidList.size(); i++) {
                String uid = uidList.get(i);
                //查询分销单事件流水
                TIrisEventHandingRecordExample example = new TIrisEventHandingRecordExample();
                example.createCriteria()
                        .andPropertyEqualTo(TIrisEventHandingRecordExample.SHARDING_ID
                                , ShardingIdUtil.sharding(uid))
                        .andPropertyEqualTo(TIrisEventHandingRecordExample.ACTIVITY_ID,
                                activityConfig.getInviteGiftActivityId())
                        .andPropertyEqualTo(TIrisEventHandingRecordExample.TASK_ID
                                , ActivityTaskIdEnum.INVITE_GMV_TASK.getCode())
                        .andPropertyEqualTo(TIrisEventHandingRecordExample.EVENT_TYPE,
                                ActivityEventTypeEnum.DISTRIBUTION_ORDER.getCode());
                List<TIrisEventHandingRecordDO> list = eventHandingRecordMapper.selectByExample(example);
                if (!CollectionUtils.isEmpty(list)) {
                    //筛选出符合条件（查询流水表在0701零点后分销单交易成功的消息(orderStatus=SUCCESS,finishTime不为空，
                    // 下单时间在改团长成为见习之后并且晚于0701零点)）
                    List<TIrisEventHandingRecordDO> collect = list.stream().filter(item ->
                            checkEventHandingRecord(item,UserTaskStatusEnum.LIMITED))
                            .collect(Collectors.toList());
                    if (!CollectionUtils.isEmpty(collect) && collect.size() > 0) {
                        //如果符合条件（将任务完成状态和预估完成状态修改为进行中，is_participated置为未受限）
                        updateUserTaskRecord(uid);
                        //将流水表交易成功消息重新投递，走新逻辑处理任务
                        TIrisEventHandingRecordDO eventHandingRecordDO = collect.get(0);
                        TaskRetry(eventHandingRecordDO,uid);
                        uidSet.add(uid);
                    }
                }
            }
        }
        response.setUidList(uidSet);
        return response;
    }

    private void TaskRetry(TIrisEventHandingRecordDO eventHandingRecordDO,String uid){
        String eventInfoJson = eventHandingRecordDO.getEventInfo();
        ActivityEventDTO eventDTO = JSON.parseObject(eventInfoJson, ActivityEventDTO.class);
        String activityBizId = eventHandingRecordDO.getActivityId();
        String taskBizId = eventHandingRecordDO.getTaskId();
        ActivityDTO activityDTO = irisActivityService.getActivity(activityBizId);
        ActivityTaskDTO taskDTO = irisActivityTaskService.getTaskByTaskBizId(taskBizId);
        IrisTaskExecutor taskHandler = eventExecutorContext.getTaskHandler(taskBizId);
        if (taskHandler == null) {
            log.error("营销事件重试：找不到对应的IrisTaskExecutor uid:{}, taskBizId:{}", uid, taskBizId);
            return;
        }
        TaskExecutorExtendInfo extendInfo = new TaskExecutorExtendInfo();
        extendInfo.setInviteGiftCheckGmv(true);
        taskHandler.execute(eventDTO, activityDTO, taskDTO, extendInfo);
    }

    private void updateUserTaskRecord(String uid){
        //更新任务进度记录
        TIrisUserTaskRecordExample example = new TIrisUserTaskRecordExample();
        example.createCriteria()
                .andPropertyEqualTo(TIrisUserTaskRecordExample.SHARDING_ID, ShardingIdUtil.sharding(uid))
                .andPropertyEqualTo(TIrisUserTaskRecordExample.UID, uid)
                .andPropertyEqualTo(TIrisUserTaskRecordExample.ACTIVITY_ID, activityConfig.getInviteGiftActivityId())
                .andPropertyEqualTo(TIrisUserTaskRecordExample.TASK_ID,ActivityTaskIdEnum.INVITE_GMV_TASK.getCode())
                .andPropertyEqualTo(TIrisUserTaskRecordExample.USER_TASK_STATUS,UserTaskStatusEnum.LIMITED.getCode());
        TIrisUserTaskRecordDO updateDO = new TIrisUserTaskRecordDO();
        updateDO.setUserTaskStatus(UserTaskStatusEnum.PROGRESS.getCode());
        updateDO.setEstimateUserTaskStatus(UserTaskStatusEnum.PROGRESS.getCode());
        updateDO.setIsParticipated(TaskBatchDateIsParticipatedEnum.YES.getCode());
        updateDO.setUpdateTime(new Date());
        userTaskRecordMapper.updateByExampleSelective(updateDO, example);
    }

    private boolean checkEventHandingRecord(TIrisEventHandingRecordDO eventHandingRecordDO,UserTaskStatusEnum userTaskStatusEnum) {
        String eventInfo = eventHandingRecordDO.getEventInfo();
        String uid = eventHandingRecordDO.getUid();
        ActivityEventDTO orderEventDTO = JsonUtils.parse(eventInfo, ActivityEventDTO.class);
        String eventInfoContent = orderEventDTO.getEventInfo();
        if (StringUtils.isBlank(eventInfoContent)) {
            return false;
        }
        DistributionOrderEvent orderEvent = JsonUtils.parse(eventInfoContent, DistributionOrderEvent.class);
        String orderStatus = orderEvent.getOrderStatus();
        Long finishTime = orderEvent.getFinishTime();
        Long orderCreateTime = orderEvent.getOrderCreateTime();
        Long gmv = orderEvent.getGmv();

        if (StringUtils.isNotBlank(orderStatus)
                && orderStatus.equals(OrderStatusEnum.SUCCESS.getCode())
                && Objects.nonNull(finishTime) && Objects.nonNull(orderCreateTime)
                && orderCreateTime >= activityCommonService.queryInviteUpperLimitChangeTime(uid)
                && Objects.nonNull(gmv) && gmv > 0) {
            //查询邀请有礼任务记录
            TIrisUserTaskRecordDO userTaskRecordDO = queryUserTaskRecord(uid);
            if (Objects.isNull(userTaskRecordDO)) {
                return false;
            }
            if (userTaskRecordDO.getStatus() != ActivityTaskStatusEnum.NORMAL.getCode()) {
                return false;
            }
            //任务状态过滤
            Byte userTaskStatus = userTaskRecordDO.getUserTaskStatus();
            if (Objects.nonNull(userTaskStatusEnum) && userTaskStatusEnum.getCode() != userTaskStatus) {
                return false;
            }
            //获取成为见习时间
            Long traineeTime = userTaskRecordDO.getCurrentTaskStartTime().getTime();
            if (traineeTime < activityCommonService.queryInviteUpperLimitChangeTime(uid)) {
                return false;
            }
            //获取任务开始时间、任务结束时间
            LocalDate currentTaskStartDate = userTaskRecordDO.getCurrentTaskStartTime().toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDate();
            LocalDate currentTaskEndDate = userTaskRecordDO.getCurrentTaskEndTime().toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDate();
            LocalDate localDate = new Date(orderCreateTime).toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDate();
            //下单时间在成为见习后
            if (LocalDateUtil.isLocalDateBetween(localDate, currentTaskStartDate, currentTaskEndDate)) {
                return true;
            }
        }
        return false;
    }

    private TIrisUserTaskRecordDO queryUserTaskRecord(String uid){
        QueryUserTaskRecordFromDBRequest request = QueryUserTaskRecordFromDBRequest
                .builder().uid(uid).activityId(activityConfig.getInviteGiftActivityId())
                .taskId(ActivityTaskIdEnum.INVITE_GMV_TASK.getCode()).build();
        return irisUserTaskRecordService.queryUserTaskRecord(request);
    }

    @SneakyThrows
    @Override
    public InviteDataFreshResponse inviteTaskStatusDeal(InviteDataFreshRequest request) {
        InviteDataFreshResponse response = new InviteDataFreshResponse();
        //查询任务记录表中任务开始时间在0701-0706之间任务状态为受限的记录
        List<String> uidList = request.getUidList();
        if (!CollectionUtils.isEmpty(uidList)) {
            response.setTotalNum(uidList.size());
            for (int i = 0; i < uidList.size(); i++) {
                String uid = uidList.get(i);
                //查询任务记录
                TIrisUserTaskRecordDO irisUserTaskRecordDO = queryUserTaskRecord(uid);
                //将任务完成状态和预估完成状态修改为进行中，is_participated置为未受限
                updateUserTaskRecord(uid);
                //模拟发送佣金变更消息
                JSONObject eventInfo = new JSONObject();
                String orderTimeStr = TimeUtils.parse(new Date(), TimeUtils.YYYY_MM_DD);
                eventInfo.put("orderTime",orderTimeStr);
                ActivityEventDTO eventDTO = ActivityEventDTO.builder().uid(uid)
                        .pid(irisUserTaskRecordDO.getPid())
                        .eventType(ActivityEventTypeEnum.COMMISSION_CHANGE.getCode())
                        .eventTime(irisUserTaskRecordDO.getCurrentTaskStartTime().getTime())
                        .idempotent(idCreateorUtil.genId())
                        .eventSource(ActivityEventSourceEnum.ADMIN_OPERATE.getCode())
                        .eventInfo(eventInfo.toJSONString())
                        .build();
                userEventListener.handleEvent(JSON.toJSONString(eventDTO));
            }
        }
        return response;
    }

    @Override
    public InviteDataFreshResponse queryLimitPid(InviteDataFreshRequest request) {
        InviteDataFreshResponse response = new InviteDataFreshResponse();
        List<TIrisEventHandingRecordDO> listAll = new ArrayList<>();
        for (int i = 0; i < 1024; i++) {
            //分片获取满足邀请有礼门槛的分销单消息
            List<TIrisEventHandingRecordDO> list = queryEventHandingRecord(request,i);
            if (!CollectionUtils.isEmpty(list)) {
                //过滤满足7月邀请有礼条件的交易成功订单消息
                List<TIrisEventHandingRecordDO> eventHandingRecordDOList = list.stream().filter(item ->
                        checkEventHandingRecord(item,null))
                        .collect(Collectors.toList());
                listAll.addAll(eventHandingRecordDOList);
            }
        }
        //查询受限的pid
        List<String> pidSet = listAll.stream().map(TIrisEventHandingRecordDO::getPid)
                .distinct()
                .filter(item -> isAwardLimit(request, item))
                .collect(Collectors.toList());

        response.setPidList(pidSet);
        //是否更新进度表的交易完成时间
        if (BooleanUtils.isTrue(request.getUpdateOrderFinishTime())) {
            //将所有满足的交易成功的订单进行排序
            List<DistributionOrderEvent> orderList = listAll.stream()
                    .map(item -> {
                        ActivityEventDTO orderEventDTO = JsonUtils.parse(item.getEventInfo(), ActivityEventDTO.class);
                        String eventInfoContent = orderEventDTO.getEventInfo();
                        return JsonUtils.parse(eventInfoContent, DistributionOrderEvent.class);
                    })
                    .sorted(Comparator.comparingLong(a -> a.getFinishTime()))
                    .collect(Collectors.toList());

            //更新进度表的交易完成时间
            Set<String> uidSet = new HashSet<>();
            if (!CollectionUtils.isEmpty(orderList)){
                orderList.forEach(item ->{
                    if (!uidSet.contains(item.getCpsUid())) {
                        updateUserTaskRecordOrderFinishTime(item.getCpsUid(),item.getFinishTime());
                    }
                    uidSet.add(item.getCpsUid());
                });
            }
            response.setUidList(uidSet);
        }
        return response;
    }

    @Override
    public InviteDataFreshResponse updateUserIsParticipated(InviteDataFreshRequest request) {
        List<String> uidList = request.getUidList();
        if (!CollectionUtils.isEmpty(uidList)) {
            for (int i = 0; i < uidList.size(); i++) {
                String uid = uidList.get(i);
                TIrisUserTaskRecordExample example = new TIrisUserTaskRecordExample();
                example.createCriteria()
                        .andPropertyEqualTo(TIrisUserTaskRecordExample.SHARDING_ID, ShardingIdUtil.sharding(uid))
                        .andPropertyEqualTo(TIrisUserTaskRecordExample.UID, uid)
                        .andPropertyEqualTo(TIrisUserTaskRecordExample.ACTIVITY_ID, activityConfig.getInviteGiftActivityId())
                        .andPropertyEqualTo(TIrisUserTaskRecordExample.TASK_ID,ActivityTaskIdEnum.INVITE_GMV_TASK.getCode());
                TIrisUserTaskRecordDO updateDO = new TIrisUserTaskRecordDO();
                updateDO.setIsParticipated(request.getIsParticipated());
                updateDO.setUpdateTime(new Date());
                userTaskRecordMapper.updateByExampleSelective(updateDO, example);
            }

        }
        return null;
    }

    private boolean isAwardLimit(InviteDataFreshRequest request, String pid) {
        Date parse = TimeUtils.parse(request.getStartTime());
        long becomeTraineeTime = parse.getTime();
        DateTime begin = DateUtil.beginOfMonth(new Date(becomeTraineeTime));
        DateTime end = DateUtil.endOfMonth(new Date(becomeTraineeTime));
        AwardRecordRequest awardRecordRequest = new AwardRecordRequest()
                .setAwardIssueStatus(Arrays.asList(AwardRecordIssueStatusEnum.ISSUE_SUCCEED.getCode()))
                .setActivityIds(Arrays.asList(ActivityIdEnum.INVITE_GIFT))
                .setTaskIds(Arrays.asList(ActivityTaskIdEnum.INVITE_GMV_TASK))
                .setStartTime(begin.getTime())
                .setEndTime(end.getTime()).setUid(pid);
        BoolQueryBuilder commonQuery = activityAwardRecordService.getCommonQuery(awardRecordRequest);
        long l = activityAwardRecordService.esCountDistinctPrecise(commonQuery, TIrisActivityAwardRecordExample.UID, pid);
        Integer num = Math.toIntExact(l);
        String monthStr = DateUtil.format(new Date(becomeTraineeTime), "yyyyMM");
        InviteLimitDTO result = activityCommonService.queryUserInviteLimit(pid, monthStr);
        if (Objects.isNull(result)) {
            return false;
        }
        if (num <= result.getInviteLimit()) {
            return false;
        }
        return true;
    }

    private void updateUserTaskRecordOrderFinishTime(String uid, Long finishTime) {
        //更新任务进度记录
        TIrisUserTaskRecordExample example = new TIrisUserTaskRecordExample();
        example.createCriteria()
                .andPropertyEqualTo(TIrisUserTaskRecordExample.SHARDING_ID, ShardingIdUtil.sharding(uid))
                .andPropertyEqualTo(TIrisUserTaskRecordExample.UID, uid)
                .andPropertyEqualTo(TIrisUserTaskRecordExample.ACTIVITY_ID, activityConfig.getInviteGiftActivityId())
                .andPropertyEqualTo(TIrisUserTaskRecordExample.TASK_ID,ActivityTaskIdEnum.INVITE_GMV_TASK.getCode());
        TIrisUserTaskRecordDO updateDO = new TIrisUserTaskRecordDO();
        updateDO.setOrderFinishTime(new Date(finishTime));
        updateDO.setUpdateTime(new Date());
        userTaskRecordMapper.updateByExampleSelective(updateDO, example);
    }

}
